package gitee.cheungming.modules.governance.service;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.zaxxer.hikari.HikariDataSource;
import gitee.cheungming.modules.governance.domain.EnvironmentData;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.sql.*;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class EnvironmentService {

    @Resource(name = "tdengineDataSource")
    HikariDataSource tdengineDataSource;

    String tablePrefix = "environment_data_";

    public void ingestion(List<EnvironmentData> dataList) {

        int batchSize = 5000;

        String sql = "insert into data_middle_platform.dmp_environment_data" +
                " (tbname, ts, latitude, longitude, temperature,humidity,battery,vin,device_id,device_type) " +
                "values (?,?,?,?,?,?,?,?,?,?)";
        try (Connection conn = tdengineDataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            long start = System.currentTimeMillis();
            int count = 0;
            for (EnvironmentData data : dataList) {
                pstmt.setString(1, tablePrefix + data.getVin());
                pstmt.setTimestamp(2, data.getTs());
                pstmt.setDouble(3, data.getLatitude());
                pstmt.setDouble(4, data.getLongitude());
                pstmt.setFloat(5, data.getTemperature());
                pstmt.setFloat(6, data.getHumidity());
                pstmt.setFloat(7, data.getBattery());
                pstmt.setString(8, data.getVin());
                pstmt.setString(9, data.getDeviceId());
                pstmt.setString(10, data.getDeviceType());
                pstmt.addBatch();

                if (++count % batchSize == 0) {
                    int[] batch = pstmt.executeBatch();
                    log.info("已提交: {} 条,成功：{}条", batchSize, batch.length);
                }

                if (count % 10_000 == 0) {
                    double rate = count / ((System.currentTimeMillis() - start) / 1000.0);
                    log.info("已插入:{}条, 速率{}条/秒%n", count, rate);
                }
            }

            pstmt.executeBatch();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }

    public List<EnvironmentData> createData(long totalPoints) {
        final Instant start = Instant.parse("2025-03-01T00:00:00Z");
        final long step = 30;
        List<EnvironmentData> list = new ArrayList<>();
        for (int i = 0; i < totalPoints; i++) {
            Instant timestamp = start.plus(i * step, ChronoUnit.SECONDS);
            EnvironmentData environmentData = new EnvironmentData();
            environmentData.setTs(new Timestamp(timestamp.toEpochMilli()));
            environmentData.setVin("d" + RandomUtil.randomInt(0, 9999));
            environmentData.setLatitude(39.9);
            environmentData.setLongitude(116.3);
            environmentData.setTemperature(RandomUtil.randomFloat(0, 50));
            environmentData.setHumidity(RandomUtil.randomFloat(0, 100));
            environmentData.setBattery(RandomUtil.randomFloat(0, 100));
            environmentData.setDeviceId("d" + RandomUtil.randomInt(0, 9999));
            environmentData.setDeviceType("d" + RandomUtil.randomInt(0, 9999));
            list.add(environmentData);
        }
        log.info("数据条数：" + list.size());
        log.info(JSONUtil.toJsonStr(list.get(0)));
        log.info(JSONUtil.toJsonStr(list.get(list.size() - 1)));
        return list;
    }


    public EnvironmentData queryLatest(String vin) {
        EnvironmentData environmentData = new EnvironmentData();
        String sql = "select ts, latitude, longitude, temperature,humidity,battery,vin,device_id,device_type" +
                " from data_middle_platform.dmp_environment_data where vin=?";
        try (Connection conn = tdengineDataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, vin);

            ResultSet resultSet = pstmt.executeQuery();

            while (resultSet.next()) {
                environmentData = convert(resultSet);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
        return environmentData;
    }

    public List<EnvironmentData> queryHistory(String vin, Timestamp start, Timestamp end) {
        List<EnvironmentData> list = new ArrayList<>();

        String sql = "select ts, latitude, longitude, temperature,humidity,battery,vin,device_id,device_type" +
                " from data_middle_platform.dmp_environment_data " +
                "where vin=? and ts >=? and ts< ?";
        try (Connection conn = tdengineDataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, vin);
            pstmt.setTimestamp(2, start);
            pstmt.setTimestamp(3, end);

            ResultSet resultSet = pstmt.executeQuery();
            System.out.println(sql);


            while (resultSet.next()) {
                list.add(convert(resultSet));
            }


        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
        return list;
    }

    public EnvironmentData convert(ResultSet resultSet) throws SQLException {
        EnvironmentData environmentData = new EnvironmentData();
        environmentData.setTs(resultSet.getTimestamp("ts"));
        environmentData.setLatitude(resultSet.getDouble("latitude"));
        environmentData.setLongitude(resultSet.getDouble("longitude"));
        environmentData.setTemperature(resultSet.getFloat("temperature"));
        environmentData.setHumidity(resultSet.getFloat("humidity"));
        environmentData.setBattery(resultSet.getFloat("battery"));
        environmentData.setVin(resultSet.getString("vin"));
        environmentData.setDeviceId(resultSet.getString("device_id"));
        environmentData.setDeviceType(resultSet.getString("device_type"));
        return environmentData;
    }
}
